#ifndef  SELFTWORKLAYER_GLOBALS
#define  SELFTWORKLAYER_GLOBALS
#include <includes.h>
#include "WF_BuildVolt.h"
#include "WF_Volatility.h"
#include "WF_ExtExcitation.h"
#include "WF_LowFreProte.h"
#include "WF_StartStop.h"

/**
 * @brief 屏蔽告警跳过停机
 * 
 * @param TempOutAlarm 
 * @param FilterTable 
 * @return uint8_t 
 */
uint8_t FilterOverShutDownAlarm(uint8_t *TempOutAlarm,uint8_t* FilterTable)
{
    while (*FilterTable!=0xFF)
    {
        uint8_t num = *(FilterTable++);
        uint8_t byteIndex = num / 8;
        uint8_t bitIndex = num  % 8;

        TempOutAlarm[byteIndex] &= (0 << bitIndex);
    }
    
	if(SwitchAlarmStatusByTable(NULL,CfgOperaType_None,TempOutAlarm,OutAlarmWarnSwitchTable))
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmShutDown,BitOperaOpt_Set);
    else
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmShutDown,BitOperaOpt_Clr);
	return (DEF_FALSE);
}


/**
 * @brief  Set New Workflow Mode
 * @param  none
 * @return none.
 */
void SetNewWorkflowModeStatus(uint8_t *TempWorkflow, uint8_t *TempWFStep,uint8_t *TempWFPeriod,  uint8_t *WFStaChange, uint8_t NewMode)
{
    *TempWorkflow = NewMode;
    *TempWFStep = WorkflowStep_Entry;
    *TempWFPeriod = WorkflowPeriod_Entry;
    *WFStaChange = DEF_TRUE;
}
/**
 * @brief  Set New Workflow Step
 * @param  none
 * @return none.
 */
void SetNewWorkFlowStepStatus(uint8_t *TempWFStep,uint8_t *TempWFPeriod, uint8_t *WFStaChange, uint8_t NewStep)
{
    *TempWFStep = NewStep;
    *TempWFPeriod = WorkflowPeriod_Entry;//复原第一周期
    *WFStaChange = DEF_TRUE;
}
void SetNextNewWorkFlowStepStatus(uint8_t *TempWFStep,uint8_t *TempWFPeriod, uint8_t *WFStaChange, uint8_t MaxStep)
{
    if(*TempWFStep+1>MaxStep)
        *TempWFStep = MaxStep;
    else
        *TempWFStep = ++*TempWFStep;
    *TempWFPeriod = WorkflowPeriod_Entry;//复原第一周期
    *WFStaChange = DEF_TRUE;
}
/**
 * @brief  Set New Workflow Period
 * @param  none
 * @return none.
 */
void SetNewWorkFlowPeriodStatus(uint8_t *TempWFPeriod, uint8_t *WFStaChange, uint8_t NewPeriod)
{
    *TempWFPeriod = NewPeriod;
    *WFStaChange = DEF_TRUE;
}
/**
 * @brief  Update Workflow Mode
 * @param  none
 * @return none.
 */
void UpdateWorkflowModeStatus(uint8_t *TempWorkflow, uint8_t *TempWFStep,uint8_t *TempWFPeriod,  uint8_t *WFStaChange)
{
    /* Update Workflow Mode */
    if (*WFStaChange)
    {
        FillShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_WorkflowStep, *TempWFStep, 1);
        FillShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_WorkflowPeriod, *TempWFPeriod, 1);
        FillShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_WorkflowMode, *TempWorkflow, 1);
    }
}


/** 功能：在每个流程中都使用此函数检查在当前转态下是否存在停机告警筛选表中所列出的停机告警
  * 输入：TempWorkflow，TempWFPeriod，WFStaChange 用于更新设置新流程
  TempGenWorkingSta= ，TempOutAlarm= ，ActInform= ，Solution=
  * 返回：
  */
static uint8_t ShutDownAlarm_WorkFlowHandle(uint8_t *TempWorkflow,uint8_t *TempWFStep,uint8_t *TempWFPeriod,uint8_t *WFStaChange,uint8_t *TempOutAlarm,uint8_t *ActInform,uint8_t Solution)
{
  if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_GenWorkingSta,GenWorkStaOrd_AlarmShutDown))//检查控制器的运行状态是否在停机告警态
  {
  	if(Solution&GenFaultWay_Action)
    {
      SetNewWorkflowModeStatus(TempWorkflow,TempWFStep,TempWFPeriod,WFStaChange,WorkflowMode_StopPriMover);
    }
    return(DEF_TRUE);
  }
  
  return(DEF_FALSE);
}

/**
 * @brief 流程公共函数  合闸前检查
 * 
 * @param TempWorkflow 
 * @param TempWFStep 
 * @param TempWFPeriod 
 * @param Step_Maximum 
 * @param EngineInitStart_time 
 * @param EngineInitSpeed 
 * @return uint8_t 
 */
uint8_t SwitchBefCheckStep(uint8_t TempWorkflow,uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t Step_Maximum,uint16_t EngineInitStart_time,uint16_t EngineInitSpeed,ShutDownAlarmCALLBACK ShutDownAlarmCallback)
{
    uint8_t ActInform = DEF_FALSE,WFStaChange = DEF_FALSE;
    if (TempWFPeriod == WorkflowPeriod_Entry)
    {
        // 励磁分压到低限位(控制两个电机)
        if(PidReqExcvLimVal(30))
            SetNewWorkFlowPeriodStatus(&TempWFPeriod,&WFStaChange,WorkflowPeriod_1st);
    }
    else if(TempWFPeriod == WorkflowPeriod_1st)
    {
        /* AlarmShutDown     */
        if(ShutDownAlarmCallback(&TempWFStep,&TempWFPeriod,&WFStaChange,GenFaultWay_ALL))
        {
            UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
            return (ActInform);
        }
        if(GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_SharePIDOrderSta[ShareInOrderSta_ExcvLimVal])==PIDOrderSta_DEF_SUCCESS)
        {
            SetNewWorkFlowPeriodStatus(&TempWFPeriod,&WFStaChange,WorkflowPeriod_2nd);
            //断开励磁分流器1 2
            ModifyFlagShareBufferDataContent(NULL,CfgOperaType_None,ShareBuffer_Outputs,RelayOutput_EXCI_SW,BitOperaOpt_Clr);
            ActInform |= WorkflowOutRequestBit_RelayOut;
        }
    }
    else if(TempWFPeriod == WorkflowPeriod_2nd)
    {
        // 原动机启动或停止
        if(share_parameterCfgData_st.estaMagnCfg_st.EngineInitSpeed>=5)
        {
            if(PidReqPriMoverStartStop(EngineInitSpeed,EngineInitStart_time,PriMover_ENUM_Type_Start,EngineInitStart_time+5,ShareInOrderSta_PriMoverStart))
                SetNewWorkFlowPeriodStatus(&TempWFPeriod,&WFStaChange,WorkflowPeriod_3nd);
        }
        else
        {
            if(PidReqPriMoverStartStop(EngineInitSpeed,EngineInitStart_time,PriMover_ENUM_Type_Stop,EngineInitStart_time+5,ShareInOrderSta_PriMoverStop))
                SetNewWorkFlowPeriodStatus(&TempWFPeriod,&WFStaChange,WorkflowPeriod_3nd);
        }
    }
    else if(TempWFPeriod == WorkflowPeriod_3nd)
    {
        /* AlarmShutDown     */
        if(ShutDownAlarmCallback(&TempWFStep,&TempWFPeriod,&WFStaChange,GenFaultWay_ALL))
        {
            UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
            return (ActInform);
        }
        // 判断开机停机
        if(share_parameterCfgData_st.estaMagnCfg_st.EngineInitSpeed>=5)
        {
            if(GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_SharePIDOrderSta[ShareInOrderSta_PriMoverStart])==PIDOrderSta_DEF_SUCCESS)
            {
                SetNextNewWorkFlowStepStatus(&TempWFStep,&TempWFPeriod,&WFStaChange,Step_Maximum);
            }
        }
        else
        {
            if(GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_SharePIDOrderSta[ShareInOrderSta_PriMoverStop])==PIDOrderSta_DEF_SUCCESS)
            {
                SetNextNewWorkFlowStepStatus(&TempWFStep,&TempWFPeriod,&WFStaChange,Step_Maximum);
            }
        }
    }

    /* Update Workflow--Step and Mode */
    UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
    return (ActInform);
}



static uint8_t WorkFlowHandling_Standby(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE, WFStaChange = DEF_FALSE;
    uint8_t ReStartWorkflowMode = GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_ReStartWorkflowMode);

    if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_GenWorkingSta,GenWorkStaOrd_AlarmReset))
    {
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmReset,BitOperaOpt_Clr);
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmShutDown,BitOperaOpt_Clr);
        FillShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_RawAlarm,0,RawAlarm_TOTByteNum);
        DigitalInputsRawCloseSta = 0;
    }

    // 清除紧急停机
    if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_RawAlarm,RawAlarm_EmergencyStop))
        ModifyFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_RawAlarm,RawAlarm_EmergencyStop,BitOperaOpt_Clr);

    if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_GenWorkingSta,GenWorkStaOrd_ManualStart))
    {   
        ChangeGenWorkingSta(GenWorkStaOrd_ManualStart,BitOperaOpt_Clr);
        if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_GenWorkingSta,GenWorkStaOrd_AlarmShutDown)==DEF_FALSE)
        {
            SetNewWorkflowModeStatus(&TempWorkflow,&TempWFStep,&TempWFPeriod,&WFStaChange,ReStartWorkflowMode);
            ChangeGenWorkingSta(GenWorkStaOrd_Running,BitOperaOpt_Set);
        }
    }

    /************************************/
    /* Update Workflow--Step and Mode */
    UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
    return (ActInform);
}

static uint8_t WorkFlowHandling_LoadUnLoad(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE;
    return (ActInform);
}
static uint8_t WorkFlowHandling_Tuning0APF(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE;
    return (ActInform);
}
static uint8_t WorkFlowHandling_Tuning08PF(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE;
    return (ActInform);
}
static uint8_t WorkFlowHandling_Tuning06A04PF(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE;
    return (ActInform);
}
static uint8_t WorkFlowHandling_CloseGate(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE;
    return (ActInform);
}
static uint8_t WorkFlowHandling_StopPriMover(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE,WFStaChange = DEF_FALSE;
    if (TempWFPeriod == WorkflowPeriod_Entry)
    {
        if(PidReqPriMoverStartStop(0,10,PriMover_ENUM_Type_Stop,10+5,ShareInOrderSta_PriMoverStop))
        {
            SetNewWorkFlowPeriodStatus(&TempWFPeriod,&WFStaChange,WorkflowPeriod_1st);
            SMTimerCounter = 20 * WorkFlowTimingFreq;
        }
    }
    else
    {
        if(GetFlagShareBufferDataContent(NULL,CfgOperaType_None,FlagShareBuffer_RawAlarm,RawAlarm_StopPriMotor_Fail)|| SMTimerCounter==0 ||\
            GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_SharePIDOrderSta[ShareInOrderSta_PriMoverStop])==PIDOrderSta_DEF_SUCCESS)
        {
            SetNewWorkflowModeStatus(&TempWorkflow,&TempWFStep,&TempWFPeriod,&WFStaChange,WorkflowMode_Ending);
            FillShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_SharePIDOrderSta[ShareInOrderSta_PriMoverStop],PIDOrderSta_DEF_NONE,1);
        }
    }
    /************************************/
    /* Update Workflow--Step and Mode */
    UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
    return (ActInform);
}

static uint8_t WorkFlowHandling_Ending(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
    uint8_t ActInform = DEF_FALSE,WFStaChange = DEF_FALSE;
    if (TempWFPeriod == WorkflowPeriod_Entry)
    {
        SetNewWorkflowModeStatus(&TempWorkflow,&TempWFStep,&TempWFPeriod,&WFStaChange,WorkflowMode_Standby);
        ChangeGenWorkingSta(GenWorkStaOrd_Running,BitOperaOpt_Clr);
    }
    /************************************/
    /* Update Workflow--Step and Mode */
    UpdateWorkflowModeStatus(&TempWorkflow, &TempWFStep,&TempWFPeriod, &WFStaChange);
    return (ActInform);
}
/* 工作流程 */
typedef uint8_t (*WorkFlowHandlingType)(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm);
static const WorkFlowHandlingType WorkFlowHandlingTable[WorkflowMode_TOTNum] = {
    (WorkFlowHandlingType)WorkFlowHandling_Standby        ,
    (WorkFlowHandlingType)WorkFlowHandling_BuildUpVoltage ,
    (WorkFlowHandlingType)WorkFlowHandling_Volatility     ,
    (WorkFlowHandlingType)WorkFlowHandling_ExtExcitation  ,
    (WorkFlowHandlingType)WorkFlowHandling_LowFreProte    ,
    (WorkFlowHandlingType)WorkFlowHandling_Tuning0APF     ,
    (WorkFlowHandlingType)WorkFlowHandling_Tuning08PF     ,
    (WorkFlowHandlingType)WorkFlowHandling_Tuning06A04PF  ,
    (WorkFlowHandlingType)WorkFlowHandling_LoadUnLoad     ,
    (WorkFlowHandlingType)WorkFlowHandling_StartStop      ,
    (WorkFlowHandlingType)WorkFlowHandling_CloseGate      ,
    (WorkFlowHandlingType)WorkFlowHandling_StopPriMover   ,
    (WorkFlowHandlingType)WorkFlowHandling_Ending         ,
};

/* Workflow Handling */
static uint8_t WorkflowWorkLayerHandle(uint8_t TempWorkflow, uint8_t TempWFStep,uint8_t TempWFPeriod, uint8_t *TempOutAlarm)
{
	/* Workflow Handling */
	return ((*WorkFlowHandlingTable[TempWorkflow])(TempWorkflow, TempWFStep, TempWFPeriod, TempOutAlarm));
}

uint8_t SwitchAlarmStatusByTable(void *Pevent, uint8_t OperaType, uint8_t *TempOutAlarm, uint8_t *Table)
{
	uint8_t i, os_err, Status = DEF_FALSE,num,byteIndex,bitIndex;

	/* Request control right*/
	if (OperaType == CfgOperaType_OSSem)
		OSSemPend((OS_EVENT *)Pevent, 0, &os_err);

    while (*Table!=0xFF)
    {
        num = *(Table++);
        byteIndex = num / 8;
        bitIndex = num % 8;

        if ((TempOutAlarm[byteIndex] & (1 << bitIndex)) != DEF_FALSE) {
            Status = DEF_TRUE;
            break;
        }
    }
    
    // for (i = 0; i < Number; i++,Table++) {
    //     num = *Table;
    //     byteIndex = (num - 1) / 8;
    //     bitIndex = (num - 1) % 8;

    //     if ((TempOutAlarm[byteIndex] & (1 << bitIndex)) != DEF_FALSE) {
    //         Status = DEF_TRUE;
    //         break;
    //     }
    // }

	/* Release control right*/
	if (OperaType == CfgOperaType_OSSem)
	{
		if (OSSemPost((OS_EVENT *)Pevent) != OS_ERR_NONE)
			SYS_DebugERROR; /* Error- Only for Debug */
	}

	return (Status);
}


uint8_t AlarmHandleRequestWorkLayerHandle(uint8_t TempWorkflow, uint8_t *ActInform,uint8_t* TempOutAlarm)
{
	if(SwitchAlarmStatusByTable(NULL,CfgOperaType_None,TempOutAlarm,OutAlarmWarnSwitchTable))
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmShutDown,BitOperaOpt_Set);
    else
        ChangeGenWorkingSta(GenWorkStaOrd_AlarmShutDown,BitOperaOpt_Clr);
	return (DEF_FALSE);
}

/* SelfWork Request */
uint8_t SelfTimingWFWorkLayerHandle(uint8_t TempWorkflow,uint8_t* TempShareOutAlarm)
{
    uint8_t ActInform = DEF_FALSE,TempWFStep,TempWFPeriod;

	TempWFStep = GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_WorkflowStep);
	TempWFPeriod = GetShareBufferDataContent(App_Sem_WORKFLOW, CfgOperaType_OSSem, &ShareBuffer_WorkflowPeriod);
    if (TempWFPeriod > WorkflowPeriod_Maximum)
        TempWFPeriod = WorkflowPeriod_Maximum;

    // ActInform |= InOrderHandleRequestWorkLayerHandle(TempWorkflow, &ActInform);
    ActInform |= AlarmHandleRequestWorkLayerHandle(TempWFStep,&ActInform,TempShareOutAlarm);

	/* Work flow */
	ActInform |= WorkflowWorkLayerHandle(TempWorkflow, TempWFStep, TempWFPeriod, TempShareOutAlarm);
    return (ActInform);
}
#endif